package com.evil.common.es.dto.application.order.data;

import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.order.data.ControlDataValueDTO;
import com.evil.common.es.dto.application.order.ESOrderDataDTO;
import com.evil.common.es.util.ESFieldUtil;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.InnerField;
import org.springframework.data.elasticsearch.annotations.MultiField;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * 控件值 ES实体
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Data
@Accessors(chain = true)
public class ESControlDataDTO {

    public static final String COL_ODI = "order_data_id";
    public static final String COL_CI = "control_id";
    public static final String COL_CC = "control_code";
    public static final String COL_CT = "control_title";
    public static final String COL_PCI = "parent_control_id";
    public static final String COL_TV = "table_values";
    public static final String COL_TVN = "table_values_nested";
    public static final String COL_V = "values";
    public static final String COL_VN = "values_nested";
    public static final String COL_R = "row";

    public static final String COL_DN_ODI = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_ODI);

    public static final String COL_D_CI = ESFieldUtil.join(ESOrderDataDTO.COL_DATA, COL_CI);
    public static final String COL_DN_CI = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_CI);
    public static final String COL_DN_TVN_CI = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_TVN, COL_CI);
    public static final String COL_DN_TVN_R_CI = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_TVN, COL_R, COL_CI);

    public static final String COL_DN_CC = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_CC);

    public static final String COL_DN_CT = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_CT);

    public static final String COL_DN_PCI = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_PCI);

    public static final String COL_DN_TVN = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_TVN);

    public static final String COL_DN_V = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_V);
    public static final String COL_DN_VN = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_VN);

    public static final String COL_DN_V_R = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_V, COL_R);
    public static final String COL_DN_VN_R = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_VN, COL_R);
    public static final String COL_DN_TVN_R = ESFieldUtil.join(ESOrderDataDTO.COL_DN, COL_TVN, COL_R);

    /**
     * 数据id
     */
    @NotNull
    @Field(name = COL_ODI, type = FieldType.Long)
    private Long orderDataId;

    /**
     * 控件id
     */
    @NotNull
    @Field(name = COL_CI, type = FieldType.Long)
    private Long controlId;

    /**
     * 控件code
     */
    @NotNull
    @MultiField(mainField = @Field(name = COL_CC, type = FieldType.Text, fielddata = true),
            otherFields = {
                    @InnerField(suffix = "keyword", type = FieldType.Keyword, ignoreAbove = 256)
            }
    )
    private String controlCode;

    /**
     * 控件标题
     */
    @NotNull
    @MultiField(mainField = @Field(name = COL_CT, type = FieldType.Text, fielddata = true),
            otherFields = {
                    @InnerField(suffix = "keyword", type = FieldType.Keyword, ignoreAbove = 256)
            }
    )
    private String controlTitle;

    /**
     * 上级控件id
     */
    @NotNull
    @Field(name = COL_PCI, type = FieldType.Long)
    private Long parentControlId;

    /**
     * 表格数据
     */
    @Valid
    @Field(name = COL_TV, type = FieldType.Object)
    private List<List<ESControlDataDTO>> tableValues;

    /**
     * 表格数据
     */
    @Valid
    @Field(name = COL_TVN, type = FieldType.Nested)
    private List<List<ESControlDataDTO>> tableValuesNested;

    /**
     * 控件值
     */
    @Valid
    @Field(name = COL_V, type = FieldType.Object)
    private List<ESControlDataValueDTO> values;

    /**
     * 控件值
     */
    @Valid
    @Field(name = COL_VN, type = FieldType.Nested)
    private List<ESControlDataValueDTO> valuesNested;

    /**
     * 当前所在行
     */
    @Field(name = COL_R, type = FieldType.Nested)
    private List<ESTableRowDTO> row;

    public ESControlDataDTO() {
        this.tableValues = new ArrayList<>();
        this.values = new ArrayList<>();
    }

    public ESControlDataDTO(ControlDataDTO controlDataDTO, BiFunction<String, ControlDataValueDTO, String> getDataValue) {
        this.orderDataId = controlDataDTO.getOrderDataId();
        this.controlId = controlDataDTO.getControlId();
        this.controlCode = controlDataDTO.getControlCode();
        this.controlTitle = controlDataDTO.getControlTitle();
        this.parentControlId = controlDataDTO.getParentControlId();
        this.tableValues = controlDataDTO.getTableValues().stream()
                .map(list -> list.stream().map(e -> new ESControlDataDTO(e, getDataValue)).toList())
                .collect(Collectors.toList());

        AtomicInteger i = new AtomicInteger();
        this.tableValuesNested = controlDataDTO.getTableValues().stream()
                .map(list -> {
                    List<ESControlDataDTO> row = list.stream().map(e -> new ESControlDataDTO(e, getDataValue)).collect(Collectors.toList());
                    row.forEach(cell -> {
                        cell.getValues().forEach(v -> v.setSort(i.get()));
                        cell.setRow(row.stream().map(ESTableRowDTO::new).toList());
                    });
                    i.getAndIncrement();
                    return row;
                })
                .collect(Collectors.toList());

        this.values = ESControlDataValueDTO.toESControlDataValueDTO(controlDataDTO.getValues(), this.controlCode, getDataValue);
        this.valuesNested = this.values;
    }

    public static List<ESControlDataDTO> toESControlDataDTO(List<ControlDataDTO> controlDataDTOS, BiFunction<String, ControlDataValueDTO, String> getDataValue) {
        return controlDataDTOS.stream().map(e -> new ESControlDataDTO(e, getDataValue)).collect(Collectors.toList());
    }

    public void setValues(List<ESControlDataValueDTO> values) {
        this.values = values;
        this.valuesNested = values;
    }

    public void setValuesNested(List<ESControlDataValueDTO> valuesNested) {
        this.values = valuesNested;
        this.valuesNested = valuesNested;
    }

    public ControlDataDTO toControlDataDTO() {
        ControlDataDTO controlDataDTO = new ControlDataDTO();
        controlDataDTO.setOrderDataId(this.orderDataId);
        controlDataDTO.setControlId(this.controlId);
        controlDataDTO.setControlCode(this.controlCode);
        controlDataDTO.setControlTitle(this.controlTitle);
        controlDataDTO.setParentControlId(this.parentControlId);
        controlDataDTO.setTableValues(this.tableValues.stream()
                .map(list -> list.stream().map(ESControlDataDTO::toControlDataDTO).toList())
                .toList());
        controlDataDTO.setValues(this.values.stream().map(ESControlDataValueDTO::toControlDataValueDTO).toList());

        return controlDataDTO;
    }

}
